﻿using Core.Framework.Model.Common;
using Core.Framework.Util;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.Extensions.Primitives;
using System;
using System.Threading.Tasks;

namespace Core.Middleware.DynamicApi
{
    public class DynamicApiMidWare
    {
        private readonly RequestDelegate requestDelegate;

        public DynamicApiMidWare(RequestDelegate requestDelegate)
        {
            this.requestDelegate = requestDelegate;
        }

        public async Task Invoke(HttpContext context)
        {

            string value = context.Request.Path.ToString().TrimStart('/');

            string PATH = this.GetRequestPATH(value, context.Request.Headers, context);

            if (CoreStartupHelper.IsDebug & string.IsNullOrWhiteSpace(PATH))
            {

                context.Request.Headers.TryGetValue("Referer", out StringValues referer);

                if (!string.IsNullOrWhiteSpace(referer))
                {
                    if (referer.ToString().Contains("/swagger/"))
                    {
                        PATH = value;
                    }
                }
            }

            if (string.IsNullOrWhiteSpace(PATH))
            {
                await context.Response.WriteAsync(new
                {
                    code = 404,
                    info = "Your behavior is irregular."
                }.TryToJson());
            }
            else
            {
                context.Request.Path = $"/{PATH}";

                await requestDelegate(context);
            }

        }


        /// <summary>
        /// 解密密文
        /// 拿到真正的PATH
        /// </summary>
        /// <returns></returns>
        string GetRequestPATH(string value, IHeaderDictionary header, HttpContext context)
        {
            // 获取时间戳
            decimal.TryParse(header["itool-timespan"], out decimal timeSpan);

            // 获取客户端Code
            var clientCode = header["itool-clientcode"].ToString();

            // var date = ConvertStringToDateTime(timeSpan);

            // 检测数据是否合法
            // 1. timeSpan  > 0
            // 2. clientCode 不为空
            // 3. 20s 之内（待定）
            if (timeSpan > 0 && !string.IsNullOrWhiteSpace(clientCode))
            {
                // 计算密钥
                var key = this.GetSecretSeed(timeSpan, clientCode);

                // 密钥写入上下文
                context.Items.Add("EncryptKey", key);

                // 计算地址
                return AESEncrypt.Decrypt(value, key);
            }
            else
            {
                // 数据不合法直接返回Null
                return "";
            }
        }


        /// <summary>
        /// 获取密钥种子
        /// </summary>
        /// <param name="TimeSpan">时间戳</param>
        /// <param name="ClientCode">客户端编码</param>
        /// <returns></returns>
        string GetSecretSeed(decimal timeSpan, string clientCode)
        {

            var clientId = GetHashCode(clientCode);

            string[] result = new string[16];

            char[] seed = $"{timeSpan / 2}{clientId / 3}".ToCharArray();

            for (var i = 0; i < 16; i++)
            {

                var item = seed[i].ToString();

                if (string.IsNullOrWhiteSpace(item))
                {
                    result[i] = (i + "0").Substring(0, 1);
                }
                else
                {
                    result[i] = item;
                }
            }

            return string.Join("", result);

        }

        /// <summary>
        /// 获取字符串摘要
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        int GetHashCode(string str)
        {
            int hash = 0;
            if (str.Length == 0) return hash;

            for (int i = 0; i < str.Length; i++)
            {
                int ccc = str[i];

                hash = ((hash << 5) - hash) + ccc;

                hash = hash & hash;
            }

            return hash > 0 ? hash : -hash;
        }

        /// <summary>        
        /// 时间戳转为C#格式时间        
        /// </summary>        
        /// <param name=”timeStamp”></param>        
        /// <returns></returns>        
        [Obsolete]
        private DateTime ConvertStringToDateTime(decimal timeStamp)
        {
            DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
            long lTime = long.Parse(timeStamp + "0000");
            TimeSpan toNow = new TimeSpan(lTime);
            return dtStart.Add(toNow);
        }

    }
}
